///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IMAGE_RASTERIZER_CSCANLINE_H_
#define _BUOLA_IMAGE_RASTERIZER_CSCANLINE_H_

#include <buola/image.h>

namespace buola { namespace img {

class CScanline_p8
{
public:
    typedef uint8_t TCover;
    typedef int16_t TCoord;

    //--------------------------------------------------------------------
    struct SSpan
    {
        TCoord x;
        TCoord mLen; // If negative, it's a solid span, covers is valid
        const TCover *mCovers;
    };

    CScanline_p8()=default;
    CScanline_p8(const CScanline_p8&)=delete;

    //--------------------------------------------------------------------
    void Reset(int pMinX,int pMaxX)
    {
        size_t lMaxLen = pMaxX - pMinX + 3;
        if(lMaxLen>mSpans.size())
        {
            mSpans.resize(lMaxLen);
            mCovers.resize(lMaxLen);
        }
        ResetSpans();
    }

    //--------------------------------------------------------------------
    void AddCell(int x,unsigned pCover)
    {
        *mCoverPtr=(TCover)pCover;
        if(x==mLastX+1&&mCurSpan->mLen>0)
        {
            mCurSpan->mLen++;
        }
        else
        {
            mCurSpan++;
            mCurSpan->mCovers=mCoverPtr;
            mCurSpan->x=(TCoord)x;
            mCurSpan->mLen=1;
        }
        mLastX=x;
        mCoverPtr++;
    }

    //--------------------------------------------------------------------
    void AddCells(int x,unsigned pLen, const TCover *pCovers)
    {
        memcpy(mCoverPtr,pCovers,pLen*sizeof(TCover));
        if(x==mLastX+1&&mCurSpan->mLen>0)
        {
            mCurSpan->mLen+=(TCoord)pLen;
        }
        else
        {
            mCurSpan++;
            mCurSpan->mCovers=mCoverPtr;
            mCurSpan->x=(TCoord)x;
            mCurSpan->mLen=(TCoord)pLen;
        }
        mCoverPtr+=pLen;
        mLastX=x+pLen-1;
    }

    //--------------------------------------------------------------------
    void AddSpan(int x, unsigned pLen, unsigned pCover)
    {
        if(x==mLastX+1&&mCurSpan->mLen < 0&&pCover==*mCurSpan->mCovers)
        {
            mCurSpan->mLen-=(TCoord)pLen;
        }
        else
        {
            *mCoverPtr=(TCover)pCover;
            mCurSpan++;
            mCurSpan->mCovers = mCoverPtr++;
            mCurSpan->x      = (TCoord)x;
            mCurSpan->mLen    = (TCoord)(-int(pLen));
        }
        mLastX = x + pLen - 1;
    }

    //--------------------------------------------------------------------
    void Finalize(int y)
    {
        mY = y;
    }

    //--------------------------------------------------------------------
    void ResetSpans()
    {
        mLastX=0x7FFFFFF0;
        mCoverPtr=&mCovers[0];
        mCurSpan=&mSpans[0];
        mCurSpan->mLen=0;
    }

    //--------------------------------------------------------------------
    int            y()         const { return mY; }
    unsigned       NumSpans() const { return unsigned(mCurSpan - &mSpans[0]); }
    const SSpan *begin()     const { return &mSpans[1]; }

private:
    int mLastX;
    int mY;
    std::vector<TCover> mCovers;
    TCover *mCoverPtr;
    std::vector<SSpan> mSpans;
    SSpan *mCurSpan;
};

/*namespace image*/ } /*namespace buola*/ }

#endif
